/*!***************************************************
 * @file: c_p_core.c
 * @brief: 通信协议的中层调度core文件
 * @author: ITHAO 
 * @date: 2018.11.02
 * @note: 给外界提供接口，负责调度comm_protocol.c的函数调度
 ****************************************************/
#include <string.h>
#include <stdlib.h>

#include "comm_protocol.h"
#include "comm_protocol_core.h"
#include "list.h"
#include "debug.h"

static int cmd_ioctl(struct comm_device *dev, unsigned int cmd, void *arg);


/**
 * @brief	初始化    
 * @param	p_comm_core     进行初始化的结构体指针  
 * @return	void
 * @note:将通信协议操作结构体进行初始化，如变量初始化，操作函数初始化
 */
void comm_core_init(struct comm_core *p_comm_core)
{
    int count = 0;

    if (!p_comm_core) {
        DEBUG("PARAM ERROR!\r\n");
        return;
    }

    /*init ops*/
    p_comm_core->ops.server_init_ops = sever_comm_init;
    p_comm_core->ops.client_init_ops = client_comm_init;
    p_comm_core->ops.send_data_ops = send_data;
    p_comm_core->ops.recv_data_ops = recv_data;
    p_comm_core->ops.analy_data_ops = analy_data;
    p_comm_core->ops.package_data_ops = package_data;

    /*init comm_data*/
    p_comm_core->data.sendfd = 0;
    p_comm_core->data.recvfd = 0;

    p_comm_core->data.send_data_packet.cmd_type = 0;
    p_comm_core->data.send_data_packet.cmd = 0;
    p_comm_core->data.send_data_packet.ack = 0;
    for (count = 0; count < DATA_MAX_NUM; count++)
        p_comm_core->data.send_data_packet.data[count] = NULL;
    
    p_comm_core->data.recv_data_packet.cmd_type = 0;
    p_comm_core->data.recv_data_packet.cmd = 0;
    p_comm_core->data.recv_data_packet.ack = 0;
    for (count = 0; count < DATA_MAX_NUM; count++)
        p_comm_core->data.recv_data_packet.data[count] = NULL;

    p_comm_core->ioctl = cmd_ioctl;

    /*init comm_device*/
    p_comm_core->dev.arg = 0;
    p_comm_core->dev.cmd = NONE;
}

/**
 * @brief	收尾    
 * @param	p_comm_core     进行收尾的结构体指针  
 * @return	void
 * @note:   将一些内存进行释放
 */
void comm_core_destory(struct comm_core *p_comm_core)
{
    int count;

    if (!p_comm_core) {
        DEBUG("PARAM ERROR!\r\n");
        return;
    }

    for (count = 0; count < DATA_MAX_NUM; count++) {
        if (p_comm_core->data.recv_data_packet.data[count])
            free(p_comm_core->data.recv_data_packet.data[count]);
    }
}

/**
 * @brief	操作函数   
 * @param	dev         里面装有cmd_ioctl所需要的入口参数
 *                      但主要作用是找到cmd_ioctl所在的结构体
 *          cmd         操作指令
 *          arg         预留入口参数
 * @return	-COMM_PARAM_NULL        入口参数为空错误
 *          -COMM_FUNC_NULL_ERR     函数指针变量为空错误
 *          -COMM_CMD_OVERSTEP_ERR  命令错误
 *          ret                     对应操作函数的返回值   
 * @note:根据cmd进行对应的操作，
 *       操作函数的形参是本函数所在结构体里面的data里的参数
 */
static int cmd_ioctl(struct comm_device *dev, 
                    unsigned int cmd, void *arg)
{
    int ret;
    uint8 *send_data = NULL;
    uint8 *recv_data = NULL;
    uint16 send_length = 0;
    uint16 recv_length = 0;
    struct comm_core *p_core = NULL;

    if (!dev) {
        DEBUG("PARAM ERROR!\r\n");
        return (-COMM_PARAM_NULL);
    }

    p_core = container_of(dev, struct comm_core, dev);

    switch (cmd) {
        case COMM_SERVER_INIT:
            if (p_core->ops.server_init_ops)
                ret = p_core->ops.server_init_ops();
            else
                ret = (-COMM_FUNC_NULL_ERR);
            break;

        case COMM_CLIENT_INIT:
            if (p_core->ops.client_init_ops)
                ret = p_core->ops.client_init_ops();
            else
                ret = (-COMM_FUNC_NULL_ERR);
            break;

        case COMM_RECV:
            if (p_core->ops.recv_data_ops && p_core->ops.analy_data_ops) {
                ret = p_core->ops.recv_data_ops(p_core->data.recvfd, 
                                                &recv_data, 
                                                &recv_length);
                if (ret < 0)
                    break;

                ret = p_core->ops.analy_data_ops(&p_core->data.recv_data_packet,
                                                recv_data,
                                                recv_length);
                free(recv_data);
                recv_data = NULL;

            } else
                ret = (-COMM_FUNC_NULL_ERR);

            break;

        case COMM_SEND:
            if (p_core->ops.send_data_ops && p_core->ops.package_data_ops) {

                ret = p_core->ops.package_data_ops(&p_core->data.send_data_packet,
                                                   &send_data,
                                                   &send_length);
           
                ret = p_core->ops.send_data_ops(p_core->data.sendfd, 
                                                send_data,
                                                send_length);
                
                free(send_data);
                send_data = NULL;

            } else
                ret = (-COMM_FUNC_NULL_ERR);
            break;

        default:
            DEBUG("The cmd is error (%d).\r\n", cmd);
            ret = (-COMM_CMD_OVERSTEP_ERR);
            break;
    }

   return ret;
}

void free_data_packet(struct data_packet *data)
{
    int count = 0;

    if (!data)
        return;

    data->cmd_type = 0;
    data->cmd = 0;
    data->ack = 0;
    for (count = 0; count < DATA_MAX_NUM; count++) {
        if (data->data[count] != NULL) {
            free(data->data[count]);
            data->data[count] = NULL;
        }
    }
}

void reset_data_packet(struct data_packet *data)
{
    int count = 0;

    if (!data)
        return;

    data->cmd_type = 0;
    data->cmd = 0;
    data->ack = 0;
    for (count = 0; count < DATA_MAX_NUM; count++) {
        data->data[count] = NULL;
    }
}

bool cpy_data_packet(struct data_packet *tar, 
                     struct data_packet *src)
{
    int len = 0;
    int count = 0;

    if(!tar || !src) 
        return FAIL;

    tar->cmd_type = src->cmd_type;
    tar->cmd = src->cmd;
    tar->ack = src->ack;
    for (count = 0; count < DATA_MAX_NUM; count++) {
        if (src->data[count]) {
            len = strlen((char *)src->data[count]) + 1;
            tar->data[count] = (uint8 *)malloc(len);
            strncpy((char *)tar->data[count], 
                    (char *)src->data[count],
                    len);
        }
    }

    return TRUE;
}

